/*******************************************************************
 *
 * Copyright (C), 2021-2022, LS, All rights reserved.
 *
 * Author      : 
 * Create Time : 2020-11-02
 * Version     : v0.1
 * Description : 
 *******************************************************************/

/*----------------------------Head file----------------------------*/
#include "string.h"
#include "app_display.h"
#include "lcd_st7735s.h"
#include "bsp_hw_config.h"
#include "user_config.h"
#include "qrencode.h"

#include "flash.h"
#include "ls_ble_sdk_config.h"

/*----------------------------macro file---------------------------*/
#define APP_DISP_LOG_EN     1
#if APP_DISP_LOG_EN
#include "log.h"
#define APP_DISP_LOG        LOG
#else
#define APP_DISP_LOG(...)
#endif

#define ONCE_BUF_MAX_BYTES_SIZE     (80*80*2)

/*----------------------------type define--------------------------*/

/*-------------------------func declarative------------------------*/
void app_disp_pixel_draw(uint16_t x, uint16_t y, uint32_t color);
void app_disp_image(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t *image_buf);

static void disp_sem_tx_wait(void);
void disp_sem_tx_done(void);
    
/*----------------------------var define---------------------------*/

struct st7735s_dev st7735sDev = {
    .set_dc = hal_disp_set_dc_pin,
    .set_rst = hal_disp_set_reset_pin,
    .set_backlight = hal_disp_set_backlight_pin,
    .delay_ms = app_delay_ms,
    .tx_data_block = hal_disp_send_block,
    .tx_data_noblock = hal_disp_send_noblock,
    .tx_wait = disp_sem_tx_wait,
    .tx_done = disp_sem_tx_done,
};

static uint8_t g_disp_buf[ONCE_BUF_MAX_BYTES_SIZE];
static bool lcd_init_state = false;

/*-----------------------------------------------------------------*/

bool app_disp_init_state_get(void)
{
    return lcd_init_state;
}

static void disp_sem_tx_wait(void)
{
    //while(false == tx_done_sem);
}

void disp_sem_tx_done(void)
{
    //APP_DISP_LOG("disp_sem_tx_done.\n");
    //tx_done_sem = true;
}


int app_disp_init(void)
{
    APP_DISP_LOG("app_disp_init.\n");
	
    hal_disp_gpio_drv_init();
    hal_disp_spi_drv_init();

    lcd_st7735s_init(&st7735sDev);

    app_disp_img_all_clear();
    APP_DISP_LOG("ST7735S init done.\n");
    lcd_init_state = true;

    return 0;
}


void app_disp_deinit(void)
{
    lcd_init_state = false;
    hal_disp_spi_drv_deinit();
    hal_disp_gpio_drv_deinit();
}


void app_disp_pixel_draw(uint16_t x, uint16_t y, uint32_t color)
{
    uint8_t buf[2];
	buf[1] = (uint8_t)(color >> 8);
	buf[0] = (uint8_t)(color & 0xFF);

    lcd_st7735s_set_win(&st7735sDev, x, y, 0, 0);
    lcd_st7735s_send_data_block(&st7735sDev, buf, 2);
}


void app_disp_rect_draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
{
    if((x+width) > LCD_W || (y+height) > LCD_H)
        return;

    uint32_t send_size = 0;
    uint32_t total_size = width*height*2;

    if((color>>8) == (color&0xFF)) {
        memset(g_disp_buf, (uint8_t)(color&0xFF), ONCE_BUF_MAX_BYTES_SIZE);
    }
    else {
        uint16 *pram = (uint16 *)g_disp_buf;
        for(int i=0;i<ONCE_BUF_MAX_BYTES_SIZE;i++)
            *pram++ = color;
    }

    lcd_st7735s_set_win(&st7735sDev, x, y, x+width-1, y+height-1);
    while(total_size > 0) {
        send_size = (total_size > ONCE_BUF_MAX_BYTES_SIZE) ? ONCE_BUF_MAX_BYTES_SIZE : total_size;
        lcd_st7735s_send_data_noblock(&st7735sDev, g_disp_buf, send_size);
        total_size -= send_size;
    }
}



void app_disp_image_draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t flash_addr)
{
    uint32_t offset = 0;
    uint32_t send_size = 0;
    uint32_t total_size = width*height*2;
    
    lcd_st7735s_set_win(&st7735sDev, x, y, x+width-1, y+height-1);
    while(total_size > 0) {
        send_size = (total_size > ONCE_BUF_MAX_BYTES_SIZE)? ONCE_BUF_MAX_BYTES_SIZE : total_size;
        //memcpy(g_disp_buf, &gImage_123[offset], send_size);
        hal_flash_read(flash_addr + offset, g_disp_buf, send_size);
        lcd_st7735s_send_data_noblock(&st7735sDev, g_disp_buf, send_size);
        total_size -= send_size;
        offset += send_size;
    }
}


void app_disp_image_draw_ex(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t* img_src)
{
    uint32_t offset = 0;
    uint32_t send_size = 0;
    uint32_t total_size = width*height*2;
    
    lcd_st7735s_set_win(&st7735sDev, x, y, x+width-1, y+height-1);
    while(total_size > 0) {
        send_size = (total_size > ONCE_BUF_MAX_BYTES_SIZE)? ONCE_BUF_MAX_BYTES_SIZE : total_size;
        lcd_st7735s_send_data_noblock(&st7735sDev, &img_src[offset], send_size);
        total_size -= send_size;
        offset += send_size;
    }
}


#if(SCHOOL_SKIP_ENABLE)
/***************** QR Code Part ***************************/

void qr_code_draw_point(uint16_t x, uint16_t y, uint16_t width, uint16_t color)
{
    uint32_t idx = (x + y*width)*2;
    g_disp_buf[idx+1] = (uint8_t)(color >> 8);
	g_disp_buf[idx] = (uint8_t)(color & 0xFF);
}


void app_disp_qrcode_draw(uint16_t x1, uint16_t y1, uint8_t point_width, const char *str)
{
    int i, j;
    int x, y;
    uint16_t x_start, y_start;
    
    //It need enough STACK size, need to modify startup_ARMCM0.s
    QRcode *qrcode = QRcode_encodeString(str, 0, QR_ECLEVEL_L, QR_MODE_8, 1);
    
    app_disp_rect_draw(x1-2, y1-2, qrcode->width*point_width+4, qrcode->width*point_width+4, COLOR_WHITE);
    APP_DISP_LOG("qrcode->width: %d.\n", qrcode->width);
    
    uint16_t qr_width = qrcode->width*point_width;
    
    for(y=0;y<qrcode->width;y++)
    {
        for(x=0;x<qrcode->width;x++)
        {
            x_start = x*point_width;
            y_start = y*point_width;
            if(qrcode->data[y*qrcode->width+x]&0x01)
            {
                for(j=0;j<point_width;j++) {
                    for(i=0;i<point_width;i++) {
                        qr_code_draw_point(x_start+i, y_start+j, qr_width, COLOR_BLACK);
                    }
                }
                //APP_DISP_LOG("#");
            }
            else
            {
                for(j=0;j<point_width;j++) {
                    for(i=0;i<point_width;i++) {
                        qr_code_draw_point(x_start+i, y_start+j, qr_width, COLOR_WHITE);
                    }
                }
                //APP_DISP_LOG(" ");
            }
        }
        //APP_DISP_LOG("\r\n");
    }
    //APP_DISP_LOG("\r\n");
    QRcode_free(qrcode);
    
    uint32_t total_size = qr_width*qr_width*2;
    APP_DISP_LOG("total_size: %d.\n", total_size);
    lcd_st7735s_set_win(&st7735sDev, x1, y1, x1+qr_width-1, y1+qr_width-1);
    lcd_st7735s_send_data_noblock(&st7735sDev, g_disp_buf, total_size);
}



/***************** Font Text Part ***************************/
void oled_dot_to_tft_dot(uint8 *in, uint8 *out, uint8 width, uint8 height,\
							uint16 font_color, uint16 bg_color)
{
    uint8 i,j,k,n,m;
    uint8 vl;
    uint16 index;

    for(j=0;j<height;j++) {
        n = j*((width+7)/8);
        for(k=0,i=0;k<((width+7)/8);k++) {
            vl = in[n];
            for(m=0;((i<width)&&(m<8));i++,m++) {
                if(vl&0x80) {
                    index = (i+j*width)*2;
                    out[index] = font_color&0xFF;
                    out[index+1] = (font_color>>8);
                }
                else {
                    index = (i+j*width)*2;
                    out[index] = bg_color&0xFF;
                    out[index+1] = (bg_color>>8);
                }
                vl <<= 1;
            }
            n++;
        }
    }
}


void app_display_text_string(uint16_t x, uint16_t y, text_info_t* info, uint32_t addr)
{
    if(info->head.font_width != FONT_WIDTH || info->head.font_height != FONT_HEIGHT)
        return;
    
    uint16_t x1 = x;
    uint16_t y1 = y;
    uint8_t buf[FONT_WIDTH*2];
    uint8_t char_width = 0;
    uint8_t str_width = info->head.char_num * FONT_WIDTH;
    uint32_t total_size = info->head.font_width *info->head.font_height *2;
    app_disp_rect_draw(x1, y1, str_width, info->head.font_height, COLOR_BLACK);
    
    for(uint8_t i=0;i<info->head.char_num;i++) {
        hal_flash_read(addr + i*info->head.font_width*2, buf, sizeof(buf));
        if(info->unicode[i] < 127) {
            char_width = FONT_WIDTH/2;
        }
        else {
            char_width = FONT_WIDTH;
        }
        if((x1 + char_width) > LCD_W) {
            x1 = x;
            y1 += info->head.font_height;
            app_disp_rect_draw(x1, y1, LCD_W, info->head.font_height, COLOR_BLACK);
        }
        oled_dot_to_tft_dot(buf, g_disp_buf, info->head.font_width, info->head.font_height, COLOR_WHITE, COLOR_BLACK);
        lcd_st7735s_set_win(&st7735sDev, x1, y1, x1+info->head.font_width-1, y1+info->head.font_height-1);
        lcd_st7735s_send_data_noblock(&st7735sDev, g_disp_buf, total_size);
        x1 += char_width;
    }
}
#endif      //#if(SCHOOL_SKIP_ENABLE)


/////////////////////////
/*const unsigned char gImage_1[2450] = {};

#include "disp_img_config.h"
void app_disp_image_fix_save(void)
{
    hal_flash_write(ICON_HEAD_START_ADDR, (uint8_t*)&gImage_1, sizeof(gImage_1));
}

void app_disp_image_draw_test(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
    uint32_t offset = 0;
    uint32_t send_size = 0;
    uint32_t total_size = width*height*2;
    
    lcd_st7735s_set_win(&st7735sDev, x, y, x+width-1, y+height-1);
    while(total_size > 0) {
        send_size = (total_size > ONCE_BUF_MAX_BYTES_SIZE)? ONCE_BUF_MAX_BYTES_SIZE : total_size;
        memcpy(g_disp_buf, &gImage_1[offset], send_size);
        lcd_st7735s_send_data_noblock(&st7735sDev, g_disp_buf, send_size);
        total_size -= send_size;
        offset += send_size;
    }
}*/

